#include <common.h>
#include <init.h>
#include <spl.h>
#include <asm/addrspace.h>
#include <asm/sections.h>
#include <asm/io.h>
#include <asm/global_data.h>
#include <spi.h>
#include <spi_flash.h>
#include <image.h>

DECLARE_GLOBAL_DATA_PTR;

void board_boot_order(u32 *spl_boot_list)
{
	int n = 0;
#ifdef CONFIG_SPI_FLASH_BAR
	spl_boot_list[n++] = BOOT_DEVICE_BOOTSPACE;
#endif

#ifdef CONFIG_SPL_SPI_FLASH_SUPPORT
	spl_boot_list[n++] = BOOT_DEVICE_SPI;
#endif
#ifdef CONFIG_SPL_MMC
	spl_boot_list[n++] = BOOT_DEVICE_MMC1;
#endif
#ifdef CONFIG_SPL_NAND_SUPPORT
	spl_boot_list[n++] = BOOT_DEVICE_NAND;
#endif
}

static unsigned int spl_get_uboot_offs(void)
{
	ulong spl_size, fdt_size;
	unsigned int offs;

	fdt_size = fdt_totalsize(gd->fdt_blob);
	spl_size = (ulong)&__image_copy_end - (ulong)_start;

	offs = (unsigned int)(spl_size + fdt_size);
	return offs;
}

#ifdef CONFIG_SPL_SPI_LOAD
unsigned int spl_spi_get_uboot_offs(struct spi_flash *flash)
{
    return spl_get_uboot_offs();
}
#endif

void spl_board_prepare_for_boot(void)
{

}

#ifdef CONFIG_SPL_DISPLAY_PRINT
void spl_display_print(void)
{
	printf("\n"
		"  _    ___   ___  _  _  ___ ___  ___  _  _\n"
		" | |  / _ \\ / _ \\| \\| |/ __/ __|/ _ \\| \\| |\n"
		" | |_| (_) | (_) | .` | (_ \\__ \\ (_) | .` |\n"
		" |____\\___/ \\___/|_|\\_|\\___|___/\\___/|_|\\_|\n"
		"\n");
}
#endif

#ifdef CONFIG_SPI_FLASH_BAR
static int spl_bootspace_load_image(struct spl_image_info *spl_image,
			      struct spl_boot_device *bootdev)
{
	struct image_header *header;
	unsigned int payload_offs;

	u8 *boot_device_base = (u8 *)(BOOT_SPACE_BASE);
	int err;

	payload_offs = spl_get_uboot_offs();

	header = spl_get_load_buffer(-sizeof(*header), sizeof(*header));

	memcpy((void *)header, boot_device_base + payload_offs, sizeof(*header));

	err = spl_parse_image_header(spl_image, header);
	if (err)
		return err;
	
	memcpy((void *)spl_image->load_addr,
			boot_device_base + payload_offs, 
			spl_image->size);

	return 0;
}

SPL_LOAD_IMAGE_METHOD("BootSpace", 1, BOOT_DEVICE_BOOTSPACE, spl_bootspace_load_image);
#endif

__weak void spl_mach_init(void)
{
//	arch_cpu_init();
}

u32 spl_boot_device(void)
{
#if defined(CONFIG_SPL_SPI_FLASH_SUPPORT)
	return BOOT_DEVICE_SPI;
#elif defined(CONFIG_SPL_MMC)
	return BOOT_DEVICE_MMC1;
#elif defined(CONFIG_SPL_NAND_SUPPORT)
	return BOOT_DEVICE_NAND;
#else
	return BOOT_DEVICE_NONE;
#endif
}

__weak int spl_sdram_init(void)
{
	register int raw_memsz asm ("k1");

	gd->arch.memorysize_total = raw_memsz & 0xff;
	gd->arch.memorysize_total = gd->arch.memorysize_total << 29;
	
	return dram_init();
}

void __noreturn board_init_f(ulong dummy)
{
	int ret;

	spl_mach_init();

	ret = spl_early_init();
	if (ret) {
		debug("spl_early_init() failed: %d\n", ret);
		hang();
	}

	preloader_console_init();

	if (spl_sdram_init()) {
		printf("spl sdram init failed\n");
		hang();
	}

	board_init_r(NULL, 0);
}
